using System;
using System.Collections.Generic;
using System.Text;
using LogParser.DA;

using System.Data;
using System.Data.OleDb;
using System.Data.SqlClient;

namespace LogParser
{
    public class DataPopulater
    {

        #region Private Member Variables

        private Parser _parser = new Parser();

        private int _mapId;
        private int _logId;
        private LogParser.Collections.WeaponList _weaponList;
        private LogParser.Collections.ClassList _classList;
        private LogParser.Collections.TeamList _teamList;
        private LogParser.Collections.CustomKillList _customKillList;
        private LogParser.Collections.ObjectList _objectList;
        private LogParser.Collections.FlagEventTypeList _flagEventTypeList;

        #endregion

        #region Public Properties

        public Parser Parser
        {
            get
            {
                return _parser;
            }
        }

        #endregion

        public DataPopulater()
        {

        }

        /// <summary>
        /// Preferred constructor
        /// </summary>
        /// <param name="parser">Populated instance of a parser object</param>
        public DataPopulater( Parser parser )
        {
            _parser = parser;
        }

        /// <summary>
        /// Persist all parser data to the database
        /// </summary>
        /// <returns>Success / Failure</returns>
        public bool PersistDataToDatabase()
        {

            _weaponList = new LogParser.Collections.WeaponList();
            _classList = new LogParser.Collections.ClassList();
            _teamList = new LogParser.Collections.TeamList();
            _customKillList = new LogParser.Collections.CustomKillList();
            _objectList = new LogParser.Collections.ObjectList();
            _flagEventTypeList = new LogParser.Collections.FlagEventTypeList();


            _mapId = GetMapIdByName( _parser.Match.Map );
            _logId = GetNextID( "LogFiles", "LogId" );

            if ( _parser == new Parser() )
                throw new Exception( "Please use the overloaded DataPopulater( ref Parser ) constructor before using this method" );


            bool populateResult = true;


            PersistLog();
            PersistPlayers();
            PersistKills();
            PersistCaptures();
            PersistCaptureBlocks();
            PersistChat();
            PersistDominations();
            PersistRevenges();
            PersistEngineering();
            PersistMedicChargeDeployed();
            PersistSuicides();
            PersistFlagEvent();

            PersistMatch();


            return populateResult;
        }

        #region PersistLog()

        private void PersistLog()
        {
            DA.DataObjects.LogFilesDSTableAdapters.LogFilesTableAdapter ta = TableAdapters.LogFilesTableAdapter();

            int matchTotalLength = 0;
            matchTotalLength = _parser.Match.TotalLength;

            // If match total length < 0, then the final time wasn't reported correctly in the log file.
            // Do a calculation based on the last kill to occur.
            if ( matchTotalLength < 0 )
            {
                _parser.Match.MatchEndTime = _parser.KillList[ _parser.KillList.Count - 1 ].KillTime;
                matchTotalLength = _parser.Match.TotalLength;
            }


            ta.LogFilesInsert( _logId, _parser.Match.LogFileName, _parser.Match.LogFileName, _parser.Match.LogFilePath, DateTime.Now, _mapId,
                                    _parser.Match.RedFinalScore, _parser.Match.BlueFinalScore, _parser.Match.MatchStartTime,
                                    _parser.Match.MatchEndTime, matchTotalLength, _parser.LeagueId );
        }

        #endregion

        private void PersistMatch()
        {
            DA.DataObjects.MatchesDSTableAdapters.MatchesTableAdapter mta = TableAdapters.MatchesTableAdapter();
            DA.DataObjects.MatchPlayerListDSTableAdapters.MatchPlayerListTableAdapter mplta = TableAdapters.MatchPlayerListTableAdapter();

            int nextMatchId = GetNextID( "Matches", "MatchId" );

            mta.MatchesInsert( nextMatchId, _parser.Match.RedFinalScore, _parser.Match.BlueFinalScore, _parser.Match.MatchStartTime, _parser.Match.MatchEndTime, _logId, _mapId );

            foreach ( Player player in _parser.PlayerList.Values )
            {
                int nextMatchPlayerListId = GetNextID( "MatchPlayerList", "MatchPlayerListId" );
                GameObjects.Team tempTeam = _teamList.GetTeam( player.Team );

                mplta.MatchPlayerListInsert( nextMatchPlayerListId, nextMatchId, player.PlayerId, tempTeam.ID );

            }

        }

        private void PersistCaptures()
        {
            DA.DataObjects.CapturesDSTableAdapters.CapturesTableAdapter cta = TableAdapters.CapturesTableAdapter();
            DA.DataObjects.CaptureListDSTableAdapters.CaptureListTableAdapter clta = TableAdapters.CaptureListTableAdapter();

            foreach ( Capture capture in _parser.CaptureEventList )
            {

                int nextCaptureId = GetNextID( "Captures", "CaptureId" );

                GameObjects.Team captureTeam = _teamList.GetTeam( capture.Team );


                cta.CapturesInsert( nextCaptureId, capture.DateTime, capture.CPName, capture.CPNumber, null, null, _mapId, _logId, captureTeam.ID );

                foreach ( Player player in capture.CapturingPlayerList )
                {
                    int nextCaptureListId = GetNextID( "CaptureList", "CaptureListId" );

                    clta.CaptureListInsert( nextCaptureListId, nextCaptureId, player.PlayerId );
                }
            }
        }

        private void PersistCaptureBlocks()
        {

            DA.DataObjects.CaptureBlocksDSTableAdapters.CaptureBlocksTableAdapter cbta = TableAdapters.CaptureBlocksTableAdapter();

            foreach ( CaptureBlock captureBlock in _parser.CaptureBlockEventList )
            {
                int nextCaptureBlockId = GetNextID( "CaptureBlocks", "CaptureBlockId" );

                cbta.CaptureBlocksInsert( nextCaptureBlockId, captureBlock.DateTime, captureBlock.CPNumber, captureBlock.CPName, _logId, null, null, _mapId, captureBlock.Player.PlayerId );
            }

        }

        private void PersistChat()
        {
            DA.DataObjects.ChatLogDSTableAdapters.ChatLogTableAdapter clta = TableAdapters.ChatLogTableAdapter();

            foreach ( ChatLog chat in _parser.ChatList )
            {
                GameObjects.Team team = _teamList.GetTeam( chat.Team );

                int nextChatId = GetNextID( "ChatLog", "ChatLogId" );
                clta.ChatLogInsert( nextChatId, chat.PlayerInfo.PlayerId, team.ID, chat.Text, chat.DateTime, _logId, null, null, chat.ChatType );

            }

        }

        private void PersistDestructions()
        {

            DA.DataObjects.DestructionsDSTableAdapters.DestructionsTableAdapter dta = TableAdapters.DestructionsTableAdapter();

            foreach ( Destruction destruction in _parser.DestructionList )
            {
                int nextDestructionId = GetNextID( "Destructions", "DestructionId" );

                int weaponId = _weaponList.GetWeapon( destruction.WeaponName ).WeaponID;

                dta.DestructionsInsert( nextDestructionId, destruction.DateTime, destruction.AttackingPlayer.PlayerId, destruction.VictimPlayer.PlayerId, _mapId, null, null, weaponId, _logId, destruction.DateTime );

            }

        }

        private void PersistDominations()
        {
            DA.DataObjects.DominationsDSTableAdapters.DominationsTableAdapter dta = TableAdapters.DominationsTableAdapter();

            foreach ( Domination domination in _parser.DominationList )
            {
                GameObjects.Class attackerClass = _classList.GetClass( domination.DominatingPlayer.CurrentClass );
                GameObjects.Class victimClass = _classList.GetClass( domination.VictimPlayer.CurrentClass );

                int nextDominationId = GetNextID( "Dominations", "DominationId" );
                dta.DominationsInsert( nextDominationId, domination.DateTime, domination.DominatingPlayer.PlayerId, domination.VictimPlayer.PlayerId, null, null, _mapId, 
                    _logId, domination.DateTime, attackerClass.ID, victimClass.ID );

            }
        }

        private void PersistRevenges()
        {
            DA.DataObjects.RevengesDSTableAdapters.RevengesTableAdapter rta = TableAdapters.RevengesTableAdapter();

            foreach ( Revenge revenge in _parser.RevengeList )
            {

                int nextRevengeId = GetNextID( "Revenges", "RevengeId" );
                rta.RevengesInsert( nextRevengeId, revenge.DateTime, revenge.RevengingPlayer.PlayerId, revenge.VictimPlayer.PlayerId, null, null, _mapId, _logId, revenge.DateTime );

            }

        }

        private void PersistEngineering()
        {
            DA.DataObjects.EngineeringDSTableAdapters.EngineeringTableAdapter eta = TableAdapters.EngineeringTableAdapter();

            foreach ( Engineering engineering in _parser.EngineeringList )
            {

                int nextEngineeringId = GetNextID( "Engineering", "EngineeringId" );

                GameObjects.Object objectBuilt = _objectList.GetObject( engineering.ObjectBuilt );

                eta.EngineeringInsert( nextEngineeringId, DateTime.Now, objectBuilt.ID, null, null, _mapId, _logId, DateTime.Now, engineering.PlacementPosition.X, engineering.PlacementPosition.Y, engineering.PlacementPosition.Z );

            }
        }

        private void PersistFlagEvent()
        {

            DA.DataObjects.FlagDSTableAdapters.FlagTableAdapter fta = TableAdapters.FlagTableAdapter();

            foreach ( Flag flag in _parser.FlagEventList )
            {

                int nextFlagId = GetNextID( "Flag", "FlagId" );
                GameObjects.FlagEventType flagEvent = _flagEventTypeList.GetFlagEventType( flag.EventType );


                fta.FlagInsert( nextFlagId, flag.Player.PlayerId, flag.DateTime, flag.Position.X, flag.Position.Y, flag.Position.Z, flagEvent.ID, _logId, _mapId, null, null );

            }

        }

        private void PersistMedicChargeDeployed()
        {

            DA.DataObjects.MedicChargeDSTableAdapters.MedicChargeTableAdapter mcta = TableAdapters.MedicChargeTableAdapter();

            foreach ( MedicCharge charge in _parser.MedicChargeList )
            {

                int nextMedicChargeId = GetNextID( "MedicCharge", "ChargeId" );

                mcta.MedicChargeInsert( nextMedicChargeId, charge.DateTime, charge.Player.PlayerId, null, null, _mapId, _logId, charge.DateTime, charge.EventType );

            }

        }

        private void PersistSuicides()
        {

            DA.DataObjects.SuicidesDSTableAdapters.SuicidesTableAdapter sta = TableAdapters.SuicidesTableAdapter();

            foreach ( Suicide suicide in _parser.SuicideList )
            {
                int nextSuicideId = GetNextID( "Suicides", "SuicideId" );

                GameObjects.Weapon weapon = _weaponList.GetWeapon( suicide.WeaponName );
                GameObjects.Class tempClass = _classList.GetClass( suicide.ClassName );

                sta.SuicidesInsert( nextSuicideId, suicide.Player.PlayerId, tempClass.ID, weapon.WeaponID, suicide.DateTime, _logId, null, null, _mapId, suicide.SuicidePosition.X, suicide.SuicidePosition.Y, suicide.SuicidePosition.Z );

            }

        }


        #region PersistKills()

        private void PersistKills()
        {
            DA.DataObjects.KillsDSTableAdapters.KillsTableAdapter kta = TableAdapters.KillsTableAdapter();

            foreach ( Kill kill in _parser.KillList )
            {
                string weaponName = kill.Weapon;
                int customKillId = 0;

                GameObjects.Weapon weapon = _weaponList.GetWeapon( weaponName );
                int weaponId = weapon.WeaponID;

                GameObjects.Class attackerClass = _classList.GetClass( kill.AttackerClass );
                GameObjects.Class victimClass = _classList.GetClass( kill.VictimClass );

                GameObjects.Team attackerTeam = _teamList.GetTeam( kill.AttackerTeam );
                GameObjects.Team victimTeam = _teamList.GetTeam( kill.VictimTeam );


                if ( kill.CustomKill != string.Empty )
                    customKillId = _customKillList.GetCustomKill( kill.CustomKill ).CustomKillID;

                int nextKillId = GetNextID( "Kills", "KillId" );

                kta.KillsInsert( nextKillId, null, null, kill.KillTime, kill.Attacker.PlayerId, weaponId, attackerClass.ID,
                    kill.AttackerPosition.X, kill.AttackerPosition.Y, kill.AttackerPosition.Z,
                    attackerTeam.ID, kill.Victim.PlayerId,
                    kill.VictimPosition.X, kill.VictimPosition.Y, kill.VictimPosition.Z,
                    victimTeam.ID, victimClass.ID, _mapId, customKillId, _logId, kill.KillTime );

                PersistAssists( kill, nextKillId );

            }
        }

        #endregion

        #region PersistAssists()

        private void PersistAssists( Kill kill, int killId )
        {
            DA.DataObjects.AssistDSTableAdapters.AssistsTableAdapter ata = TableAdapters.AssistsTableAdapter();


            foreach ( Assist assist in kill.Assists )
            {
                GameObjects.Class assistClass = _classList.GetClass( assist.AssistClassName );

                int nextAssistId = GetNextID( "Assists", "AssistId" );

                ata.AssistsInsert( nextAssistId, assist.DateTime, killId, assist.AssistPlayer.PlayerId, kill.Victim.PlayerId, kill.AttackerPosition.X, kill.AttackerPosition.Y, kill.AttackerPosition.Z, assist.AssistPosition.X, assist.AssistPosition.Y, assist.AssistPosition.Z, kill.VictimPosition.X, kill.VictimPosition.Y, kill.VictimPosition.Z, _logId, null, null, _mapId, assistClass.ID, assist.Type.ToString() );

            }

        }

        #endregion

        private void PersistPlayers()
        {
            DA.DataObjects.PlayersDSTableAdapters.PlayersTableAdapter ta = TableAdapters.PlayersTableAdapter();
            DA.DataObjects.PlayerNameListDSTableAdapters.PlayerNameListTableAdapter nlta = TableAdapters.PlayerNameListTableAdapter();

            foreach ( Player player in _parser.PlayerList.Values )
            {
                if ( ta.PlayersSelectById( player.PlayerId ).Rows.Count == 0 )
                {

                    ta.PlayersInsert( player.PlayerId, player.FirstSeen, player.LastSeen );
                }
                else
                {
                    ta.PlayersUpdate( player.PlayerId, player.LastSeen );
                }


                foreach ( string playerName in player.PlayerNames )
                {

                    if ( nlta.PlayerNameListSelectByName( playerName ).Rows.Count == 0 )
                    {
                        int nextNameListId = GetNextID( "PlayerNameList", "PlayerNameListId" );

                        nlta.PlayerNameListInsert( nextNameListId, player.PlayerId, playerName );
                    }

                }


            }
        }

        private int GetMapIdByName( string mapShortName )
        {

            if ( mapShortName == string.Empty )
            {
                mapShortName = "cp_well";
            }

            DA.DataObjects.MapsDSTableAdapters.MapsTableAdapter mta = TableAdapters.MapsTableAdapter();
            DA.DataObjects.MapsDS.MapsDataTable mdt = mta.MapsSelectByNameGet( mapShortName );

            DA.DataObjects.MapsDS.MapsRow mapRow = (DA.DataObjects.MapsDS.MapsRow) mdt.Rows[ 0 ];

            return mapRow.MapId;

        }

        #region GetNextId + helper methods

        public static int GetNextID( string p_tableName, string p_columnName )
        {
            int returnVal;

            try
            {
                string sql = "SELECT MAX(" + p_columnName + ") FROM " + p_tableName;

                DataSet ds = Read( sql );
                returnVal = (int) ds.Tables[ 0 ].Rows[ 0 ][ 0 ];
            }
            catch ( Exception ex )
            {
                returnVal = 0;
            }

            return ( returnVal + 1 );

        }

        public static DataSet Read( string sql )
        {
            DataSet _ds = new DataSet();

            using ( SqlConnection conn = TableAdapters.GetConnection() )
            {
                try
                {
                    conn.Open();

                    SqlDataAdapter _da = new SqlDataAdapter( sql, conn );
                    _da.Fill( _ds );
                }
                catch ( Exception ex )
                {

                }
                finally
                {
                    // close the connection
                    if ( conn.State == ConnectionState.Open )
                        conn.Close();
                }
            }

            return _ds;
        }

        #endregion

    }
}
